home *** CD-ROM | disk | FTP | other *** search
- /*
- ** $VER: server.c 1.9 (20 Aug 1995)
- **
- ** magplip.device - Parallel Line Internet Protocol
- **
- ** Original code written by Oliver Wagner and Michael Balzer.
- **
- ** This version has been completely reworked by Marius Gröger, introducing
- ** slight protocol changes. The new source is a lot better organized and
- ** maintainable.
- **
- ** Additional changes and code cleanup by Jan Kratochvil and Martin Mares.
- ** The new source is significantly faster and yet better maintainable.
- **
- ** (C) Copyright 1993-1994 Oliver Wagner & Michael Balzer
- ** (C) Copyright 1995 Marius Gröger
- ** (C) Copyright 1995 Jan Kratochvil & Martin Mares
- ** All Rights Reserved
- **
- ** $HISTORY:
- **
- ** 20 Aug 1995 : 001.009 : support for ASM xfer routines
- ** removed obsolete CIA macros (mag/jk/mm)
- ** 29 Jul 1995 : 001.008 : support for arbitration delay
- ** symmetrical handling
- ** 26 Apr 1995 : 001.007 : _very_ nasty bug would miss packets and get
- ** the driver totally irritated
- ** 25 Apr 1995 : 001.006 : now compiles with ANSI and STRICT
- ** fixed bug with resource allocation
- ** 08 Mar 1995 : 001.005 : write req. are now handled by device.c
- ** 06 Mar 1995 : 001.004 : collision delay added
- ** 06 Mar 1995 : 001.003 : hardware transmission errors are no longer retried
- ** because this is any upper layers job
- ** 04 Mar 1995 : 001.002 : event tracking *much* more conform to SANA-2
- ** 18 Feb 1995 : 001.001 : startup now a bit nicer
- ** using BASEPTR
- ** 12 Feb 1995 : 001.000 : reworked original
- */
-
- #define DEBUG 0
-
- /*F*/ /* includes */
- #ifndef CLIB_EXEC_PROTOS_H
- #include <clib/exec_protos.h>
- #include <pragmas/exec_sysbase_pragmas.h>
- #endif
- #ifndef CLIB_DOS_PROTOS_H
- #include <clib/dos_protos.h>
- #include <pragmas/dos_pragmas.h>
- #endif
- #ifndef CLIB_CIA_PROTOS_H
- #include <clib/cia_protos.h>
- #include <pragmas/cia_pragmas.h>
- #endif
- #ifndef CLIB_MISC_PROTOS_H
- #include <clib/misc_protos.h>
- #include <pragmas/misc_pragmas.h>
- #endif
- #ifndef CLIB_TIME_PROTOS_H
- #include <clib/timer_protos.h>
- #include <pragmas/timer_pragmas.h>
- #endif
- #ifndef CLIB_UTILITY_PROTOS_H
- #include <clib/utility_protos.h>
- #include <pragmas/utility_pragmas.h>
- #endif
-
- #ifndef EXEC_MEMORY_H
- #include <exec/memory.h>
- #endif
- #ifndef EXEC_INTERRUPTS_H
- #include <exec/interrupts.h>
- #endif
- #ifndef EXEC_DEVICES_H
- #include <exec/devices.h>
- #endif
- #ifndef EXEC_IO_H
- #include <exec/io.h>
- #endif
-
- #ifndef DEVICES_SANA2_H
- #include <devices/sana2.h>
- #endif
-
- #ifndef HARDWARE_CIA_H
- #include <hardware/cia.h>
- #endif
-
- #ifndef RESOURCES_MISC_H
- #include <resources/misc.h>
- #endif
-
- #ifndef _STRING_H
- #include <string.h>
- #endif
-
- #ifndef __MAGPLIP_H
- #include "magplip.h"
- #endif
- #ifndef __DEBUG_H
- #include "debug.h"
- #endif
- /*E*/
-
- /*F*/ /* defines, types and enums */
-
- /*
- ** return codes for arbitratedwrite()
- */
- typedef enum { AW_OK, AW_ABORTED, AW_BUFFER_ERROR, AW_ERROR } AW_RESULT;
-
- /*E*/
- /*F*/ /* imports */
- extern VOID dotracktype(BASEPTR, ULONG type, ULONG ps, ULONG pr, ULONG bs, ULONG br, ULONG pd);
- extern VOID DevTermIO(BASEPTR, struct IOSana2Req *ios2);
- extern USHORT ASM CRC16(REG(a0) UBYTE *, REG(d0) SHORT);
- extern BOOL ASM hwsend(REG(a0) BASEPTR);
- extern BOOL ASM hwrecv(REG(a0) BASEPTR);
- extern VOID ASM interrupt(REG(a1) BASEPTR);
-
- extern FAR volatile struct CIA ciaa,ciab;
- /*E*/
- /*F*/ /* exports */
- extern VOID __saveds ServerTask(VOID);
- /*E*/
- /*F*/ /* statics */
- static struct PLIPBase *startup(void);
- static REGARGS VOID DoEvent(BASEPTR, long event);
- static VOID readargs(BASEPTR);
- static BOOL init(BASEPTR);
- static BOOL hwattach(BASEPTR);
- static VOID hwdetach(BASEPTR);
- static REGARGS BOOL goonline(BASEPTR);
- static REGARGS VOID gooffline(BASEPTR);
- static REGARGS AW_RESULT arbitratedwrite(BASEPTR, struct IOSana2Req *ios2);
- static REGARGS VOID dowritereqs(BASEPTR);
- static REGARGS VOID doreadreqs(BASEPTR);
- static REGARGS VOID dos2reqs(BASEPTR);
- /*E*/
-
- /*F*/ /* CIA access macros & functions */
-
- #define CLEARINT SetICR(CIAABase, CIAICRF_FLG)
- #define DISABLEINT AbleICR(CIAABase, CIAICRF_FLG)
- #define ENABLEINT AbleICR(CIAABase, CIAICRF_FLG | CIAICRF_SETCLR)
-
- #define SETCIAOUTPUT ciaa.ciaddrb = 0xFF
- #define SETCIAINPUT ciaa.ciaddrb = 0x00
- #define PARINIT(b) SETCIAINPUT; \
- ciab.ciaddra &= ~((b)->pb_HandshakeMask[HS_LINE]); \
- ciab.ciaddra |= (b)->pb_HandshakeMask[HS_REQUEST]
-
- #define TESTLINE(b) (ciab.ciapra & (b)->pb_HandshakeMask[HS_LINE])
- #define SETREQUEST(b) ciab.ciapra |= (b)->pb_HandshakeMask[HS_REQUEST]
- #define CLEARREQUEST(b) ciab.ciapra &= ~((b)->pb_HandshakeMask[HS_REQUEST])
-
- /*E*/
-
- /*
- ** functions to gain hardware, initialise communication
- ** and to release hardware
- */
- /*F*/ static BOOL hwattach(BASEPTR)
- {
- BOOL rc = FALSE;
-
- d(("entered\n"));
-
- if (MiscBase = OpenResource("misc.resource"))
- {
- if (CIAABase = OpenResource("ciaa.resource"))
- {
- CiaBase = CIAABase;
-
- d(("ciabase is %lx\n",CiaBase));
-
- /* obtain exclusive access to the parallel hardware */
- if (!AllocMiscResource(MR_PARALLELPORT, pb->pb_DevNode.lib_Node.ln_Name))
- {
- pb->pb_AllocFlags |= 1;
- if (!AllocMiscResource(MR_PARALLELBITS, pb->pb_DevNode.lib_Node.ln_Name))
- {
- pb->pb_AllocFlags |= 2;
-
- /* Add our interrupt to handle CIAICRB_FLG.
- ** This is also cia.resource means of granting exclusive
- ** access to the related registers in the CIAs.
- */
- pb->pb_Interrupt.is_Node.ln_Type = NT_INTERRUPT;
- pb->pb_Interrupt.is_Node.ln_Pri = 127;
- pb->pb_Interrupt.is_Node.ln_Name = SERVERTASKNAME;
- pb->pb_Interrupt.is_Data = (APTR)pb;
- pb->pb_Interrupt.is_Code = (VOID (*)())&interrupt;
-
- /* We must Disable() bcos there could be an interrupt already
- ** waiting for us. We may, however, not Able/SetICR() before
- ** we have access!
- */
- Disable();
- if (!AddICRVector(CIAABase, CIAICRB_FLG, &pb->pb_Interrupt))
- {
- DISABLEINT; /* this is what I meant */
- rc = TRUE;
- }
- Enable();
-
- if (rc)
- {
- pb->pb_AllocFlags |= 4;
- PARINIT(pb); /* cia to input, handshake in/out setting */
- CLEARREQUEST(pb); /* setup handshake lines */
- CLEARINT; /* clear this interrupt */
- ENABLEINT; /* allow interrupts */
- }
-
- }
- else
- d(("no parallelbits\n"));
- }
- else
- d(("no parallelport\n"));
- }
- else
- d(("no misc resource\n"));
- }
- else
- d(("no misc resource\n"));
-
- return rc;
- }
- /*E*/
- /*F*/ static VOID hwdetach(BASEPTR)
- {
- if (pb->pb_AllocFlags & 4)
- {
- DISABLEINT;
- CLEARINT;
- RemICRVector(CIAABase, CIAICRB_FLG, &pb->pb_Interrupt);
- }
-
- if (pb->pb_AllocFlags & 2) FreeMiscResource(MR_PARALLELBITS);
-
- if (pb->pb_AllocFlags & 1) FreeMiscResource(MR_PARALLELPORT);
-
- pb->pb_AllocFlags = 0;
- }
- /*E*/
-
- /*
- ** functions to go online/offline
- */
- /*F*/ static REGARGS VOID rejectpackets(BASEPTR)
- {
- struct IOSana2Req *ios2;
-
- ObtainSemaphore(&pb->pb_WriteListSem);
- while(ios2 = (struct IOSana2Req *)RemHead((struct List*)&pb->pb_WriteList))
- {
- ios2->ios2_Req.io_Error = S2ERR_OUTOFSERVICE;
- ios2->ios2_WireError = S2WERR_UNIT_OFFLINE;
- DevTermIO(pb,ios2);
- }
- ReleaseSemaphore(&pb->pb_WriteListSem);
-
- ObtainSemaphore(&pb->pb_ReadListSem);
- while(ios2 = (struct IOSana2Req *)RemHead((struct List*)&pb->pb_ReadList))
- {
- ios2->ios2_Req.io_Error = S2ERR_OUTOFSERVICE;
- ios2->ios2_WireError = S2WERR_UNIT_OFFLINE;
- DevTermIO(pb,ios2);
- }
- ReleaseSemaphore(&pb->pb_ReadListSem);
-
- ObtainSemaphore(&pb->pb_ReadOrphanListSem);
- while(ios2 = (struct IOSana2Req *)RemHead((struct List*)&pb->pb_ReadOrphanList))
- {
- ios2->ios2_Req.io_Error = S2ERR_OUTOFSERVICE;
- ios2->ios2_WireError = S2WERR_UNIT_OFFLINE;
- DevTermIO(pb,ios2);
- }
- ReleaseSemaphore(&pb->pb_ReadOrphanListSem);
- }
- /*E*/
- /*F*/ static REGARGS BOOL goonline(BASEPTR)
- {
- BOOL rc = FALSE;
-
- d(("trying to go online\n"));
-
- if (pb->pb_Flags & (PLIPF_OFFLINE | PLIPF_NOTCONFIGURED))
- {
- if (!hwattach(pb))
- {
- d(("error going online\n"));
- }
- else
- {
- GetSysTime(&pb->pb_DevStats.LastStart);
- pb->pb_Flags &= ~(PLIPF_OFFLINE | PLIPF_NOTCONFIGURED);
- DoEvent(pb, S2EVENT_ONLINE);
- rc = TRUE;
- d(("i'm now online!\n"));
- }
- }
-
- return rc;
- }
- /*E*/
- /*F*/ static REGARGS VOID gooffline(BASEPTR)
- {
- if (!(pb->pb_Flags & (PLIPF_OFFLINE | PLIPF_NOTCONFIGURED)))
- {
- hwdetach(pb);
-
- pb->pb_Flags |= PLIPF_OFFLINE;
-
- DoEvent(pb, S2EVENT_OFFLINE);
- }
- d(("ok!\n"));
- }
- /*E*/
-
- /*
- ** SANA-2 Event management
- */
- /*F*/ static REGARGS VOID DoEvent(BASEPTR, long event)
- {
- struct IOSana2Req *ior, *ior2;
-
- d(("event is %lx\n",event));
-
- ObtainSemaphore(&pb->pb_EventListSem );
-
- for(ior = (struct IOSana2Req *) pb->pb_EventList.lh_Head;
- ior2 = (struct IOSana2Req *) ior->ios2_Req.io_Message.mn_Node.ln_Succ;
- ior = ior2 )
- {
- if (ior->ios2_WireError & event)
- {
- Remove((struct Node*)ior);
- DevTermIO(pb, ior);
- }
- }
-
- ReleaseSemaphore(&pb->pb_EventListSem );
- }
- /*E*/
-
- /*
- ** writing packets
- */
- /*F*/ static REGARGS AW_RESULT arbitratedwrite(BASEPTR, struct IOSana2Req *ios2)
- {
- BOOL having_line;
- AW_RESULT rc;
-
- /*
- ** Arbitration
- ** ===========================================================
- **
- ** Pseudo code of the arbitration:
- **
- ** if LINE is high (other side is ready to receive) then
- ** set REQUEST high (tell the other side we're ready to send)
- ** if LINE is high (other side is still ready to receive) then
- ** we have the line, do transfer
- ** reset REQUEST to low (tell other side we're ready to receive)
- **
- ** AW_OK if we could transmit all the data correctly
- ** AW_BUFF_ERROR if the BufferManagement callback failed
- ** AW_ERROR if we got the line, but the actual transfer
- ** failed, perhaps due to a timeout
- ** AW_ABORT if we couldn't get the line
- */
-
- having_line = FALSE;
-
- if (!TESTLINE(pb)) /* is the line free ? */
- {
- SETREQUEST(pb); /* indicate our request to send */
-
- if (pb->pb_ArbitrationDelay > 0)
- {
- pb->pb_TimeReq.tr_time.tv_secs = 0;
- pb->pb_TimeReq.tr_time.tv_micro = pb->pb_ArbitrationDelay;
- pb->pb_TimeReq.tr_node.io_Command = TR_ADDREQUEST;
- DoIO((struct IORequest*)&pb->pb_TimeReq);
- }
-
- if (!TESTLINE(pb)) /* is the line still free ? */
- having_line = TRUE;
- else
- {
- if (!(pb->pb_Flags & PLIPF_RECEIVING))
- CLEARREQUEST(pb); /* reset line state */
- d2(("couldn't get the line-1\n"));
- }
- }
- else d2(("couldn't get the line-2\n"));
-
- if (having_line)
- {
- struct BufferManagement *bm;
-
- if (!(pb->pb_Flags & PLIPF_RECEIVING))
- {
- d(("having line for: typ %08lx, size %ld\n",ios2->ios2_PacketType,
- ios2->ios2_DataLength));
-
- pb->pb_SendFrame.pf_Type = ios2->ios2_PacketType;
- pb->pb_SendFrame.pf_Size = ios2->ios2_DataLength + PKTFRAMESIZE_2;
-
- bm = (struct BufferManagement *)ios2->ios2_BufferManagement;
-
- if (!(*bm->bm_CopyFromBuffer)((UBYTE*)pb->pb_SendFrame.pf_Data,
- ios2->ios2_Data, ios2->ios2_DataLength))
- {
- rc = AW_BUFFER_ERROR;
- CLEARREQUEST(pb); /* reset line state */
- }
- else
- rc = hwsend(pb) ? AW_OK : AW_ERROR;
- }
- else
- {
- d4(("arbitration error!\n"));
- rc = AW_ABORTED;
- }
- }
- else
- rc = AW_ABORTED;
-
- return rc;
- }
- /*E*/
- /*F*/ static REGARGS VOID dowritereqs(BASEPTR)
- {
- struct IOSana2Req *currentwrite, *nextwrite;
- AW_RESULT code;
-
- ObtainSemaphore(&pb->pb_WriteListSem);
-
- for(currentwrite = (struct IOSana2Req *)pb->pb_WriteList.lh_Head;
- nextwrite = (struct IOSana2Req *) currentwrite->ios2_Req.io_Message.mn_Node.ln_Succ;
- currentwrite = nextwrite )
- {
- if (pb->pb_Flags & PLIPF_RECEIVING)
- {
- d(("incoming data!"));
- break;
- }
-
- code = arbitratedwrite(pb, currentwrite);
-
- if (code == AW_ABORTED) /* arbitration failed */
- {
- pb->pb_Flags |= PLIPF_COLLISION;
- d(("couldn't get the line, trying again later\n"));
- if ((currentwrite->ios2_Req.io_Error++) > pb->pb_Retries)
- {
- currentwrite->ios2_Req.io_Error = S2ERR_TX_FAILURE;
- currentwrite->ios2_WireError = S2WERR_TOO_MANY_RETIRES;
- Remove((struct Node*)currentwrite);
- DevTermIO(pb, currentwrite);
- }
- break;
- }
- else if (code == AW_BUFFER_ERROR) /* BufferManagement callback error */
- {
- d(("buffer error\n"));
- DoEvent(pb, S2EVENT_ERROR | S2EVENT_BUFF | S2EVENT_SOFTWARE);
- currentwrite->ios2_Req.io_Error = S2ERR_SOFTWARE;
- currentwrite->ios2_WireError = S2WERR_BUFF_ERROR;
- Remove((struct Node*)currentwrite);
- DevTermIO(pb, currentwrite);
- }
- else if (code == AW_ERROR)
- {
- /*
- ** this is a real line error, upper levels (e.g. Internet TCP) have
- ** to care for reliability!
- */
- d(("error transmitting packet\n"));
- DoEvent(pb, S2EVENT_ERROR | S2EVENT_TX | S2EVENT_HARDWARE);
- currentwrite->ios2_Req.io_Error = S2ERR_TX_FAILURE;
- currentwrite->ios2_WireError = S2WERR_GENERIC_ERROR;
- Remove((struct Node*)currentwrite);
- DevTermIO(pb, currentwrite);
- }
- else /*if (code == AW_OK)*/ /* well done! */
- {
- d(("packet transmitted successfully\n"));
- pb->pb_DevStats.PacketsSent++;
- dotracktype(pb, pb->pb_SendFrame.pf_Type, 1, 0, currentwrite->ios2_DataLength, 0, 0);
- currentwrite->ios2_Req.io_Error = S2ERR_NO_ERROR;
- currentwrite->ios2_WireError = S2WERR_GENERIC_ERROR;
- Remove((struct Node*)currentwrite);
- DevTermIO(pb, currentwrite);
- }
- }
-
- ReleaseSemaphore(&pb->pb_WriteListSem);
- }
- /*E*/
-
- /*
- ** reading packets
- */
- /*F*/ static REGARGS VOID doreadreqs(BASEPTR)
- {
- LONG datasize;
- struct IOSana2Req *got;
- ULONG pkttyp;
- struct BufferManagement *bm;
-
- if (hwrecv(pb))
- {
- pb->pb_DevStats.PacketsReceived++;
-
- datasize = pb->pb_ReceiveFrame.pf_Size - PKTFRAMESIZE_2;
-
- dotracktype(pb, pkttyp = pb->pb_ReceiveFrame.pf_Type, 0, 1, 0, datasize, 0);
-
- d(("packet %08lx, size %ld received\n",pkttyp,datasize));
-
- ObtainSemaphore(&pb->pb_ReadListSem);
-
- for(got = (struct IOSana2Req *)pb->pb_ReadList.lh_Head;
- got->ios2_Req.io_Message.mn_Node.ln_Succ;
- got = (struct IOSana2Req *)got->ios2_Req.io_Message.mn_Node.ln_Succ )
- {
- if (got->ios2_PacketType == pkttyp )
- {
- Remove((struct Node*)got);
-
- bm = (struct BufferManagement *)got->ios2_BufferManagement;
-
- if (!(*bm->bm_CopyToBuffer)(got->ios2_Data, (UBYTE*)pb->pb_ReceiveFrame.pf_Data, datasize))
- {
- d(("CopyToBuffer: error\n"));
- got->ios2_Req.io_Error = S2ERR_SOFTWARE;
- got->ios2_WireError = S2WERR_BUFF_ERROR;
- DoEvent(pb, S2EVENT_ERROR | S2EVENT_BUFF | S2EVENT_SOFTWARE);
- }
- else
- {
- got->ios2_Req.io_Error = got->ios2_WireError = 0;
- }
-
- got->ios2_Req.io_Flags = 0;
- got->ios2_SrcAddr[0] = (pb->pb_Flags & PLIPF_SIDEA) ? 0 : (1<<7);
- got->ios2_DstAddr[0] = (pb->pb_Flags & PLIPF_SIDEA) ? (1<<7) : 0 ;
- got->ios2_DataLength = datasize;
-
- d(("packet received, satisfying S2Request\n"));
- DevTermIO(pb, got);
- got = NULL;
- break;
- }
- }
-
- ReleaseSemaphore(&pb->pb_ReadListSem);
- }
- else
- {
- DoEvent(pb, S2EVENT_HARDWARE | S2EVENT_ERROR | S2EVENT_RX);
-
- got = NULL;
- pb->pb_DevStats.BadData++;
- }
-
- if (got)
- {
- d(("unknown packet\n"));
-
- pb->pb_DevStats.UnknownTypesReceived++;
-
- ObtainSemaphore(&pb->pb_ReadOrphanListSem);
- got = (struct IOSana2Req *)RemHead((struct List*)&pb->pb_ReadOrphanList);
- ReleaseSemaphore(&pb->pb_ReadOrphanListSem);
-
- if (got)
- {
- bm = (struct BufferManagement *)got->ios2_BufferManagement;
- if (!(*bm->bm_CopyToBuffer)(got->ios2_Data, (UBYTE*)pb->pb_ReceiveFrame.pf_Data, datasize))
- {
- got->ios2_Req.io_Error = S2ERR_SOFTWARE;
- got->ios2_WireError = S2WERR_BUFF_ERROR;
- }
- else
- {
- got->ios2_Req.io_Error = got->ios2_WireError = 0;
- }
-
- got->ios2_Req.io_Flags = 0;
- got->ios2_SrcAddr[0] = (pb->pb_Flags & PLIPF_SIDEA) ? 0 : (1<<7);
- got->ios2_DstAddr[0] = (pb->pb_Flags & PLIPF_SIDEA) ? (1<<7) : 0 ;
- got->ios2_DataLength = datasize;
-
- d(("orphan read\n"));
-
- DevTermIO(pb, got);
- }
- else
- {
- dotracktype(pb, pkttyp, 0, 0, 0, 0, 1);
- d(("packet thrown away...\n"));
- }
- }
- }
- /*E*/
-
- /*
- ** 2nd level device command dispatcher (~SANA2IOF_QUICK)
- */
- /*F*/ static REGARGS VOID dos2reqs(BASEPTR)
- {
- struct IOSana2Req *ios2;
-
- /*
- ** Every pending IO message will be GetMsg()'ed and processed. At the
- ** end of the loop it will be DevTermIO()'ed back to the sender,
- ** _but_only_if_ it is non-NULL. In such cases the message has been
- ** put in a separate queue to be DevTermIO()'ed later (i.e. CMD_WRITEs
- ** and similar stuff).
- ** You find the same mimique in the 1st level dispatcher (device.c)
- */
- while(ios2 = (struct IOSana2Req *)GetMsg(pb->pb_ServerPort))
- {
- if (pb->pb_Flags & PLIPF_RECEIVING)
- {
- d(("incoming data!"));
- break;
- }
-
- d(("sana2req %ld from serverport\n", ios2->ios2_Req.io_Command));
-
- switch (ios2->ios2_Req.io_Command)
- {
- case S2_ONLINE:
- if (!goonline(pb))
- {
- ios2->ios2_Req.io_Error = S2ERR_NO_RESOURCES;
- ios2->ios2_WireError = S2WERR_GENERIC_ERROR;
- }
- break;
-
- case S2_OFFLINE:
- gooffline(pb);
- rejectpackets(pb); /* reject all pending requests */
- break;
-
- case S2_CONFIGINTERFACE:
- if (pb->pb_Flags & PLIPF_NOTCONFIGURED)
- {
- ios2->ios2_SrcAddr[0] = (pb->pb_Flags & PLIPF_SIDEA) ? (1<<7) : 0;
-
- if (!goonline(pb))
- {
- ios2->ios2_Req.io_Error = S2ERR_NO_RESOURCES;
- ios2->ios2_WireError = S2WERR_GENERIC_ERROR;
- }
- }
- else
- {
- ios2->ios2_Req.io_Error = S2ERR_BAD_STATE;
- ios2->ios2_WireError = S2WERR_IS_CONFIGURED;
- }
- break;
- }
-
- if (ios2) DevTermIO(pb,ios2);
- }
- }
- /*E*/
-
- /*
- ** startup,initialisation and termination functions
- */
- /*F*/ static struct PLIPBase *startup(void)
- {
- struct ServerStartup *ss;
- struct Process *we;
- struct PLIPBase *base;
- LOCALSYSBASE;
-
- we = (struct Process*)FindTask(NULL);
-
- d(("waiting for startup msg...\n"));
- WaitPort(&we->pr_MsgPort);
- ss = (struct ServerStartup *)GetMsg(&we->pr_MsgPort);
- base = ss->ss_PLIPBase;
- d(("go startup msg at %lx, PLIPBase is %lx\n", ss, ss->ss_PLIPBase));
- ReplyMsg((struct Message*)ss);
-
- return base;
- }
- /*E*/
- /*F*/ static VOID readargs(BASEPTR)
- {
- struct RDArgs *rda;
- struct PLIPConfig args = { 0 };
- BPTR plipvar, oldinput;
-
- d(("entered\n"));
-
- if (plipvar = Open(CONFIGFILE, MODE_OLDFILE))
- {
- oldinput = SelectInput(plipvar);
-
- rda = ReadArgs(TEMPLATE , (LONG *)&args, NULL);
-
- if(rda)
- {
- if (args.timeout)
- pb->pb_Timeout = *args.timeout;
-
- if (args.priority)
- SetTaskPri((struct Task*)pb->pb_Server, *args.priority);
-
- if (args.mtu && (*args.mtu <= PLIP_MAXMTU))
- pb->pb_MTU = *args.mtu;
-
- if (args.bps)
- pb->pb_ReportBPS = *args.bps;
-
- if (args.retries && (*args.retries <= PLIP_MAXRETRIES))
- pb->pb_Retries = *args.retries;
-
- if (args.sendcrc)
- pb->pb_Flags |= PLIPF_SENDCRC;
- else
- pb->pb_Flags &= ~PLIPF_SENDCRC;
-
- if (args.collisiondelay)
- pb->pb_CollisionDelay = *args.collisiondelay;
- else
- pb->pb_CollisionDelay = PLIP_DEFDELAY +
- (pb->pb_Flags & PLIPF_SIDEA) ? PLIP_DELAYDIFF : 0;
-
- if (args.arbitrationdelay)
- pb->pb_ArbitrationDelay = *args.arbitrationdelay;
- else
- pb->pb_ArbitrationDelay = PLIP_DEFARBITRATIONDELAY;
-
- FreeArgs(rda);
- }
-
- Close(SelectInput(oldinput));
- }
-
- d(("timeout %ld, pri %ld, mtu %ld, bps %ld, retries %ld, flags %08lx, delay %ld\n",
- pb->pb_Timeout, (LONG)pb->pb_Server->pr_Task.tc_Node.ln_Pri, pb->pb_MTU, pb->pb_ReportBPS, pb->pb_Retries,
- pb->pb_Flags, pb->pb_CollisionDelay));
-
- d(("left\n"));
-
- }
- /*E*/
- /*F*/ static BOOL init(BASEPTR)
- {
- BOOL rc = FALSE;
-
- if ((pb->pb_IntSig = AllocSignal(-1)) != -1)
- {
- pb->pb_IntSigMask = 1L << pb->pb_IntSig;
-
- if (pb->pb_ServerPort = CreateMsgPort())
- {
- if (pb->pb_TimerPort = CreateMsgPort())
- {
- memset((VOID*)&pb->pb_TimeReq, 0, sizeof(pb->pb_TimeReq));
- pb->pb_TimeReq.tr_node.io_Message.mn_ReplyPort = pb->pb_TimerPort;
- if (!OpenDevice( "timer.device", UNIT_MICROHZ, (struct IORequest*)&pb->pb_TimeReq, 0 ))
- {
- TimerBase = (struct Library *)pb->pb_TimeReq.tr_node.io_Device;
- readargs(pb);
- rc = TRUE;
- }
- else
- {
- d(("couldn't open timer.device"));
- }
- }
- else
- {
- d(("no timer port\n"));
- }
- }
- else
- {
- d(("no server port\n"));
- }
- }
- else
- {
- d(("no signal\n",rc));
- }
-
- d(("left %ld\n",rc));
-
- return rc;
- }
- /*E*/
- /*F*/ static VOID cleanup(BASEPTR)
- {
- struct BufferManagement *bm;
-
- gooffline(pb);
-
- while(bm = (struct BufferManagement *)RemHead((struct List *)&pb->pb_BufferManagement))
- FreeVec(bm);
-
- if (TimerBase) CloseDevice((struct IORequest*)&pb->pb_TimeReq);
- if (pb->pb_TimerPort) DeleteMsgPort(pb->pb_TimerPort);
-
- if (pb->pb_ServerPort) DeleteMsgPort(pb->pb_ServerPort);
- if (pb->pb_IntSig != -1) FreeSignal(pb->pb_IntSig);
- }
- /*E*/
-
- /*
- ** entry point, mainloop
- */
- /*F*/ extern VOID SAVEDS ServerTask(void)
- {
- BASEPTR;
-
- d(("server running\n"));
-
- if (pb = startup())
- {
- if (init(pb))
- {
- ULONG recv, portsigmask, timersigmask, wmask;
- BOOL running, timerqueued = FALSE;
-
- portsigmask = 1 << pb->pb_ServerPort->mp_SigBit;
- timersigmask = 1 << pb->pb_TimerPort->mp_SigBit;
-
- wmask = SIGBREAKF_CTRL_F | SIGBREAKF_CTRL_C | pb->pb_IntSigMask | portsigmask | timersigmask;
-
- for(running=TRUE;running;)
- {
- if (!(pb->pb_Flags & PLIPF_RECEIVING))
- recv = Wait(wmask);
- else
- SetSignal(0, pb->pb_IntSigMask);
-
- /*if (recv & pb->pb_IntSigMask)*/
- if (pb->pb_Flags & PLIPF_RECEIVING)
- {
- d(("received an interrupt\n"));
- doreadreqs(pb);
- }
-
- if (recv & portsigmask)
- {
- d(("SANA-II request(s)\n"));
- dos2reqs(pb);
- }
-
- if (recv & timersigmask)
- {
- /* pop message */
- AbortIO((struct IORequest*)&pb->pb_TimeReq);
- WaitIO((struct IORequest*)&pb->pb_TimeReq);
- timerqueued = FALSE;
- d(("timer wakeup\n"));
- }
-
- /* try now to do write requests (if any pending) */
- if (!timerqueued)
- {
- dowritereqs(pb);
-
- /* don't let the other side wait too long! */
- if (pb->pb_Flags & PLIPF_RECEIVING)
- {
- d(("received an interrupt\n"));
- SetSignal(0, pb->pb_IntSigMask);
- doreadreqs(pb);
- }
-
- /*
- ** Possible a collision has occurred, which is indicated by a
- ** special flag in PLIPBase.
- **
- ** Using timer.device we periodically will be waked up. This
- ** allows us to delay write packets in cases when we cannot get
- ** the line immediately.
- **
- ** If client and server are very close together, regarding the point
- ** of performance, the same delay time could even force multiple
- ** collisions (at least theoretical, I made no practical tests).
- ** Probably a CSMA/CD-like random-timed delay would be ideal.
- */
- if (pb->pb_Flags & PLIPF_COLLISION)
- {
- extern void KPrintF(char *,...);
-
- pb->pb_Flags &= ~PLIPF_COLLISION;
- pb->pb_TimeReq.tr_time.tv_secs = 0;
- pb->pb_TimeReq.tr_time.tv_micro = pb->pb_CollisionDelay;
- pb->pb_TimeReq.tr_node.io_Command = TR_ADDREQUEST;
- /*KPrintF("waiting %ld/%ld\n", pb->pb_TimeReq.tr_time.tv_secs, pb->pb_TimeReq.tr_time.tv_micro);*/
- SendIO((struct IORequest*)&pb->pb_TimeReq);
- timerqueued = TRUE;
- }
- }
-
- if (recv & SIGBREAKF_CTRL_C)
- {
- d(("received break signal\n"));
- running = FALSE;
- }
- }
-
- if (timerqueued)
- {
- /* finnish pending timer requests */
- AbortIO((struct IORequest*)&pb->pb_TimeReq);
- WaitIO((struct IORequest*)&pb->pb_TimeReq);
- }
- }
- else
- d(("init() failed\n"));
-
- d(("cleaning up\n"));
- cleanup(pb);
-
- /* Exec will enable it's scheduler after we're dead. */
- Forbid();
- /* signal mother we're done */
- if (pb->pb_ServerStoppedSigMask)
- Signal(pb->pb_Task, pb->pb_ServerStoppedSigMask);
- pb->pb_Flags |= PLIPF_SERVERSTOPPED;
- }
- else
- d(("no startup packet\n"));
- }
- /*E*/
-
-